package com.zmn.oms.zmn.business.impl.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.zmn.base.engineer.common.dro.foreign.engineer.ForeignEngineerBasicInfoDRO;
import com.zmn.base.engineer.dubbo.interfaces.foreign.EngineerListRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.utils.HttpUtil;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.order.OrderUploadIascBService;
import com.zmn.oms.zmn.business.interfaces.pay.OrderPayBService;
import com.zmn.pay.common.constant.PayConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述：数据上传至数据中心
 *
 * @author xiewenbing
 * @since 2022/6/22 17:52
 */
@Slf4j
@Service("uploadIascBService")
public class OrderUploadIascBServiceImpl implements OrderUploadIascBService {

    /**
     * 上传的地址
     */
    private final static String HTTP_UPLOAD_URL = "http://58.144.7.26:8871/ywfx/dataReceive/pushData.do";

    /**
     * 身份识别码
     */
    private final static String IDENTI_CODE = "vm&jCc8JFBfxgd!BASZpK@aJptiwrb6o";

    /**
     * 重庆市id
     */
    private final static int CITY_CQ_ID = 500100;

    /**
     * 授权用户名
     */
    private final static String USER_NAME = "500113_zmn";

    /**
     * 数据资源编码
     */
    private final static String DATA_TYPE = "21001";

    /**
     * DES加密key
     */
    private final static String DES_KEY = "Aj3C7ucc";

    /**
     * 时间格式
     */
    private final static String TIME_FORMAT = "yyyyMMddHHmmss";

    /**
     * 数据所属区县代码
     */
    private final static String QX_DM = "500113";

    /**
     * 上传订单id列表最大长度
     */
    private final static int UPLOAD_ID_LIST_SIZE = 500;

    /**
     * 上传开关
     */
    public static boolean POWER_ON = false;

    /**
     * 是否为测试数据
     */
    private String IS_CS = "1";

    /**
     * 是否为测试数据
     */
    @NacosValue(value = "${order.upload.iasc.cs:1}", autoRefreshed = true)
    public void setCs(String cs) {
        IS_CS = cs;
    }

    /**
     * 上传开关
     */
    @NacosValue(value = "${order.upload.iasc.power_on:false}", autoRefreshed = true)
    public void setPowerOn(boolean powerOn) {
        POWER_ON = powerOn;
    }

    @Autowired
    private OrderProductService orderProductService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private OrderWorkService orderWorkService;

    @Autowired
    private OrderPayBService orderPayBService;

    @Resource
    private RedisManager redisManager;

    @DubboReference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    private EngineerListRemoteService engineerListRemoteService;

    private final static Map<String,String> COUNTY_NAME_MAP = new HashMap<String, String>() {{
        put("万州区", "500101");
        put("涪陵区", "500102");
        put("渝中区", "500103");
        put("大渡口区", "500104");
        put("江北区", "500105");
        put("沙坪坝区", "500106");
        put("九龙坡区", "500107");
        put("南岸区", "500108");
        put("北碚区", "500109");
        put("万盛区", "500110");
        put("双桥区", "500111");
        put("渝北区", "500112");
        put("巴南区", "500113");
        put("黔江区", "500114");
        put("长寿区", "500115");
        put("江津区", "500116");
        put("合川区", "500117");
        put("永川区", "500118");
        put("南川区", "500119");
        put("两江新区", "500199");
        put("綦江县", "500222");
        put("潼南区", "500223");
        put("铜梁区", "500224");
        put("大足区", "500225");
        put("荣昌区", "500226");
        put("璧山区", "500227");
        put("梁平区", "500228");
        put("城口区", "500229");
        put("丰都区", "500230");
        put("垫江区", "500231");
        put("武隆区", "500232");
        put("忠县", "500233");
        put("开县", "500234");
        put("云阳县", "500235");
        put("奉节县", "500236");
        put("巫山县", "500237");
        put("巫溪县", "500238");
        put("石柱县", "500240");
        put("秀山县", "500241");
        put("酉阳县", "500242");
        put("彭水县", "500243");
    }};

    /**
     * 添加订单id到上传消息队列里面
     * @param orderId
     * @param logType
     * @throws OmsBaseException
     */
    @Override
    public void addUploadOrderList(Long orderId, Integer logType) throws OmsBaseException {

        // 开关判断
        if (!POWER_ON) {
            throw new OmsBaseException("上传功能关闭");
        }

        if (NumberUtil.isNullOrZero(orderId)) {
            throw new OmsBaseException("订单Id不能为Null或0");
        }

        if (NumberUtil.isNullOrZero(logType) || (!Objects.equals(logType, OrderLogConsts.ORDER_LOG_TYPE_VISIT) &&
                !Objects.equals(logType, OrderLogConsts.ORDER_LOG_TYPE_PAY))) {
            throw new OmsBaseException("日志类型不准确");
        }

        String redisKey = String.format(RedisKeyConsts.OMS_UPLOAD_IASC_ID_LIST_KEY, String.valueOf(logType));
        redisManager.lrem(redisKey, String.valueOf(orderId), 0);
        redisManager.lpush(redisKey, String.valueOf(orderId));

    }

    /**
     * 订单列表数据上传
     */
    @Override
    public void uploadOrderList() throws OmsBaseException {

        // 开关判断
        if (!POWER_ON) {
            throw new OmsBaseException("上传功能关闭");
        }

        // 日志类型
        int[] logType = {
            OrderLogConsts.ORDER_LOG_TYPE_VISIT, OrderLogConsts.ORDER_LOG_TYPE_PAY
        };

        // 分别上传
        for (int i=0; i<2; i++) {
            String redisKey = String.format(RedisKeyConsts.OMS_UPLOAD_IASC_ID_LIST_KEY, String.valueOf(logType[i]));
            if (!redisManager.exists(redisKey) || redisManager.llen(redisKey) < 0) {
                continue;
            }

            List<String> orders = redisManager.lrange(redisKey);
            List<Long> orderIds = orders.stream().map(Long::valueOf).collect(Collectors.toList());

            if (CollectionUtil.isNullOrEmpty(orderIds)) {
                continue;
            }

            // 防止数据过大 ，分组上传
            int times = orderIds.size() / UPLOAD_ID_LIST_SIZE;
            for (int n=0; n<times; n++) {

                // 防止CPU过高
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {

                }

                int beginIndex = n * UPLOAD_ID_LIST_SIZE;
                int endIndex = (n + 1) * UPLOAD_ID_LIST_SIZE;

                if (endIndex >= orderIds.size()) {
                    endIndex = orderIds.size() - 1;
                }

                this.uploadOrderData(orderIds.subList(beginIndex, endIndex), logType[i]);
            }

            redisManager.del(redisKey);
        }
    }

    /**
     * 上传数据
     * @param orderIds
     * @throws OmsBaseException
     */
    private void uploadOrderData(List<Long> orderIds, Integer logType) throws OmsBaseException {

        if (CollectionUtil.isNullOrEmpty(orderIds)) {
            throw new OmsBaseException("参数不能为Null");
        }

        log.debug("#OrderUploadIascBService#uploadOrderData [{}], [{}]", orderIds.toString(), logType);

        // 读取并组装上传数据
        StringJoiner contentList = new StringJoiner(",", "[", "]");
        for (Long orderId : orderIds) {
            String jsonContent = this.getOrderUploadJsonString(orderId, logType);
            if (StringUtil.isNotBlank(jsonContent)) {
                contentList.add(jsonContent);
            }
        }

        if (StringUtil.isBlank(contentList.toString()) || contentList.length() <= 2) {
            throw new OmsBaseException("没有需要上传的订单数据");
        }

        // post参数
        Map<String, String> postParams = new HashMap<>(6);
        postParams.put("IDENTI_CODE", IDENTI_CODE);
        postParams.put("USER_NAME", USER_NAME);
        postParams.put("DATA_TYPE", DATA_TYPE);
        postParams.put("QX_DM", QX_DM);
        postParams.put("IS_CS", IS_CS);
        postParams.put("DATA_CONTENT", desEncrypt(contentList.toString()));

        // 上传数据
        try {

            log.info("#OrderUploadIascBService#uploadOrderData url:[{}]", HTTP_UPLOAD_URL);

            String response = HttpUtil.httpPost(HTTP_UPLOAD_URL, postParams);
            if (StringUtil.isBlank(response)) {
                return;
            }

            log.info("#OrderUploadIascBService#uploadOrderData# response:[{}]", response);
            return;
        } catch (Exception e) {
            log.error("#OrderUploadIascBService#uploadOrderData# occur exception,[{}]", e.getMessage());
            throw new OmsBaseException("上传数据失败");
        }
    }

    /**
     * 拼装订单上传JSON字符串
     * @param orderId
     * @return
     */
    private String getOrderUploadJsonString(Long orderId, Integer logType) {

        if (NumberUtil.isNullOrZero(orderId)) {
            return null;
        }

        // 工单查找
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, orderId);

        // 判断
        if (Objects.isNull(orderWork) || !Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            log.debug("#OrderUploadIascBService#getOrderUploadJsonString#[{}] 工单不存在或不是新单", orderId);
            return null;
        }

        // 非重庆市不上传
        if (!Objects.equals(orderWork.getCityId(),CITY_CQ_ID)) {
            log.debug("#OrderUploadIascBService#getOrderUploadJsonString#[{}] 非重庆市", orderId);
            return null;
        }

        // 数据查询判断
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());
        if (Objects.isNull(orderDetail)) {
            log.debug("#OrderUploadIascBService#getOrderUploadJsonString#[{}] 查询不到订单详情", orderId);
            return null;
        }

        List<OrderProduct> orderProductList = orderProductService.listOrderProductByOrderId(orderWork.getOrderId());
        if (CollectionUtil.isNullOrEmpty(orderProductList)) {
            log.debug("#OrderUploadIascBService#getOrderUploadJsonString#[{}] 工单产品不存在", orderId);
            return null;
        }

        // 支付数据
        OrderPay orderPayMaster = null;
        if (Objects.equals(logType, OrderLogConsts.ORDER_LOG_TYPE_PAY)) {
            List<OrderPay> orderPayList = orderPayBService.listOrderPayByOrderId(orderWork.getOrderId());
            if (CollectionUtil.isNullOrEmpty(orderPayList)) {
                log.debug("#OrderUploadIascBService#getOrderUploadJsonString#[{}] 工单产品不存在", orderId);
                return null;
            }

            for (OrderPay orderPay : orderPayList) {
                // 师傅收款 or 进度款 及已支付、不是删除
                if ((Objects.equals(orderPay.getAmountType(), OrderPayConsts.ORDER_PAY_MASTER) ||
                        Objects.equals(orderPay.getAmountType(), OrderPayConsts.ORDER_PAY_PROGRESS)) &&
                        !Objects.equals(orderPay.getDeleted(), GlobalConsts.YES) &&
                        Objects.equals(orderPay.getPayStatus(), PayConsts.PAY_STATUS_DONE)) {
                    orderPayMaster = orderPay;
                    break;
                }
            }
        }

        // 内容组装
        Map<String,String> mapContent = new HashMap<>(32);
        mapContent.put("DDBH", String.valueOf(orderWork.getOrderId()));
        mapContent.put("DDLX", Optional.ofNullable(orderWork.getShowServCategName()).orElse(""));
        mapContent.put("FWLX", Optional.ofNullable(orderProductList.get(0).getShowProductName()).orElse(""));
        mapContent.put("DDCJSJ", DateUtil.toString(orderWork.getReceiveTime(), TIME_FORMAT));
        mapContent.put("YHBM", String.valueOf(orderWork.getUserId()));
        mapContent.put("YHXM", Optional.ofNullable(orderDetail.getContactName()).orElse(""));
        mapContent.put("YHLXDH", orderDetail.getTelephone());
        mapContent.put("XM", Optional.ofNullable(orderDetail.getUserName()).orElse(""));
        mapContent.put("LXDH" ,orderDetail.getTelephone());
        mapContent.put("ZT", OrderStatusConsts.getOrderStatusName(orderWork.getStatus()));

        StringBuilder sbAddress = new StringBuilder();
        sbAddress.append(Optional.ofNullable(orderDetail.getProvinceName()).orElse(""))
                .append(Optional.ofNullable(orderDetail.getCityName()).orElse(""))
                .append(Optional.ofNullable(orderDetail.getCountyName()).orElse(""))
                .append(Optional.ofNullable(orderDetail.getStreet()).orElse(""))
                .append(Optional.ofNullable(orderDetail.getAddress()).orElse(""));
        mapContent.put("XXDZ" ,sbAddress.toString());

        mapContent.put("JD" ,String.valueOf(orderDetail.getLongitude()));
        mapContent.put("WD" ,String.valueOf(orderDetail.getLatitude()));
        mapContent.put("SJSMSJ", DateUtil.toString(orderWork.getVisitTime()));

        String countyCode = COUNTY_NAME_MAP.get(orderDetail.getCountyName());
        if (StringUtil.isBlank(countyCode)) {
            countyCode = "500000";
        }

        mapContent.put("SJSSQX", countyCode);

        // 上门工程师
        ResponseDTO<ForeignEngineerBasicInfoDRO> responseBasicInfoDTO = engineerListRemoteService.getEngineerById(orderWork.getMasterId());
        log.debug("uploadIascBService#uploadOrderData#getEngineerById workId={} 出参={}",orderWork.getWorkId(),JSON.toJSONString(responseBasicInfoDTO));
        if (!responseBasicInfoDTO.isSuccess() || Objects.isNull(responseBasicInfoDTO.getData())) {
            mapContent.put("SMRYXM", Optional.ofNullable(orderWork.getMasterName()).orElse(""));
            mapContent.put("SMRYLXDH", Optional.ofNullable(orderDetail.getBindTelephone()).orElse(""));
        } else {
            mapContent.put("SMRYXM", Optional.ofNullable(responseBasicInfoDTO.getData().getRealName()).orElse(""));
            mapContent.put("SMRYLXDH", Optional.ofNullable(responseBasicInfoDTO.getData().getMobile()).orElse(""));
        }

        ResponseDTO<String> responseCardDTO = engineerListRemoteService.getEngineerIdcardById(orderWork.getMasterId());
        log.debug("uploadIascBService#uploadOrderData#getEngineerIdcardById workId={} 出参={}",orderWork.getWorkId(),JSON.toJSONString(responseCardDTO));
        if (responseCardDTO.isSuccess()&&StringUtil.isNotBlank(responseCardDTO.getData())) {
            mapContent.put("SMRYZJHM", responseCardDTO.getData());
        } else {
            mapContent.put("SMRYZJHM", String.valueOf(orderWork.getMasterId()));
        }

        // 支付数据
        if (Objects.nonNull(orderPayMaster) && Objects.equals(logType, OrderLogConsts.ORDER_LOG_TYPE_PAY)) {
            mapContent.put("FKSJ", DateUtil.toString(orderPayMaster.getCreateTime(), TIME_FORMAT));
            mapContent.put("ZFFS", PayConsts.getPayTypeName(orderPayMaster.getPayType()));
            mapContent.put("SFDF", Objects.equals(orderPayMaster.getAgentType(),GlobalConsts.YES) ? "是" : "否");
            mapContent.put("ZFQD", PayConsts.getPayChannelName(orderPayMaster.getPayChannelId()));
            mapContent.put("DSFLSH", orderPayMaster.getPayOutTradeNo());
            mapContent.put("ZT", "用户支付");
        }

        mapContent.put("YDSMSJ", DateUtil.toString(orderWork.getDutyTime(), TIME_FORMAT));
        mapContent.put("GXSJ", DateUtil.toString(DateUtil.getNow(), TIME_FORMAT));
        mapContent.put("SJLY", "重庆啄木鸟网络科技有限公司");
        mapContent.put("XJ_ID", QX_DM);

        // 转成JSON
        return JSON.toJSONString(mapContent);
    }

    /**
     * des 加密
     * @param content
     * @return
     */
    private static String desEncrypt(String content) {

        if (StringUtil.isBlank(content)) {
            return "";
        }

        try {
            SecretKeySpec key = new SecretKeySpec(DES_KEY.getBytes("utf-8"), "DES");
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return Base64.getEncoder().encodeToString(result); // 加密
        } catch (Exception e) {
            log.error("#OrderUploadIascBService#desEncrypt# occur exception,[{}]", e.getMessage());
        }

        return "";
    }
}
